package com.qunar.train.mock.config;

import com.google.common.base.Splitter;
import com.google.common.io.Files;

import com.qunar.train.mock.util.AegisLog;
import com.qunar.train.mock.util.FileAndDirDeepDeletion;
import com.qunar.train.mock.util.FileAndDirSearch;
import com.qunar.train.mock.util.FileCharsetCheck;
import com.qunar.train.mock.util.FileEncodeConvert;
import com.qunar.train.mock.util.QunarFileUtil;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import qunar.tc.qconfig.client.Feature;
import qunar.tc.qconfig.client.MapConfig;

import static com.qunar.train.mock.config.ChangeQconfigEnv.changeQconfigEnv;
import static com.qunar.train.mock.config.MockQconfig.getAppCode;
import static com.qunar.train.mock.config.MockQconfig.groupName;

/**
 * Created by hongzhe.yao on 2018/8/30.
 */
public class QconfigFilesDownload {
    /**
     * download online Qconfigures files, run with online, then turned to offline 模块需要的文件名，默认\t\n间隔
     *
     * @param args
     */

    private static String separator = "\n";
    private static String resourcesPath = Class.class.getClass().getResource("/").getPath().split("/target")[0] + "/src/test/resources/";
    private static String qconfigTargetDir = Class.class.getClass().getResource("/").getPath().split("/target")[0] + "/target/test-classes/" + "qconfig_test";
    //private static String configs = getFilenames().replace("\t", "").replace(" ", "");
    private static Map<String, String> appConfig = new HashMap<>();

    //Common
    private static String b_info_transform = "register_router";
    private static String qtrace = "permit.properties" + separator +
            "receiver.properties" + separator +
            "receiver-netty.properties" + separator +
            "server.properties" + separator +
            "receiver-mode.properties";
    private static String tc_qmq_client = "consumer.properties" + separator +
            "quota.properties" + separator + "broker.properties" + separator + "router.properties";
    private static String tc_public_config = "registry.properties" + separator + "zookeeper.properties";
    private static String b_info_encrypt = "register_router";
    private static String b_info_decrypt = "register_router";

    private static Boolean isNewVersion = false;
    private static Boolean isReWrite = false;
    private static Boolean isSingle = false;


    public QconfigFilesDownload(Boolean isNewVersion) {
        this.isNewVersion = isNewVersion;
        init();
    }

    public QconfigFilesDownload(Boolean isNewVersion, Boolean isReWrite) {
        this.isNewVersion = isNewVersion;
        this.isReWrite = isReWrite;
        init();
    }

    public QconfigFilesDownload(String fileName, Boolean isNewVersion, Boolean isReWrite) {
        this.isSingle = true;
        new QconfigSingleFileDownload(fileName, isNewVersion, isReWrite).excute();
    }

    private static void init() {
        deleteQconfigFile(isReWrite);
        changeQconfigEnv(false);
        getAppConfigs();
        getQconfigFileToLocal();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            AegisLog.error(e);
        }
    }

    public void excute() {
        if (isSingle) {
            return;
        } else {
            getQconfigFileToTestResources();
            for (String app : appConfig.keySet()) {
                touchFileIfNotExsit(app, appConfig.get(app));
            }
            changeQconfigEnv(true);
        }
    }

    private static Map<String, String> getAppConfigs() {
        List configFileList = new ArrayList();
        FileAndDirSearch.findFiles(resourcesPath, "qconfig.*", configFileList);
        if (configFileList.isEmpty()) {
            AegisLog.fatal("qconfig.file is none,please check!");
            return null;
        } else {
            for (Object file : configFileList) {
                String configFile = file.toString().split("/")[file.toString().split("/").length - 1].split("\\\\")[file.toString().split("\\\\").length - 1];
                AegisLog.info("configFile: " + configFile);
                if (configFile.compareTo("qconfig.file") == 0) {
                    appConfig.put(groupName, getFileNames(configFile));
                } else {
                    if (configFile.split("\\.").length == 3) {
                        String appCode = configFile.split("\\.")[1];
                        appConfig.put(appCode, getFileNames(configFile));
                    } else {
                        AegisLog.fatal("qconfig file format error!");
                    }
                }
            }
        }
        return appConfig;
    }

    public static String getFileNames(String configFile) {
        String fileNames = "";
        try {
            fileNames = Files.toString(loadConfigToFile(configFile), Charset.forName("UTF-8"));
            fileNames = fileNames.replace("\t", "").replace("\r", "").replace(" ", "");
        } catch (IOException e) {
            AegisLog.error(e);
        }
        return fileNames;
    }

    public static void deleteQconfigFile(boolean isRewrite) {
        if (isRewrite) {
            AegisLog.log("Old Qconfig Files  will be rewrited!");

            String qconfigDir = resourcesPath + "qconfig_test";
            deleteQconfigfile(qconfigDir + "/" + groupName);
            deleteQconfigfile(qconfigTargetDir + "/" + groupName);

        } else {
            AegisLog.log("Old Qconfig Files  will remains, only add new Qconfig files!");
        }
    }

    public static void deleteQconfigfile(String Dictionary) {

        Map<String, String> configFiles = getAppConfigs();

        File targetFile = new File(Dictionary);
        String[] qconfigTargetDirlist = targetFile.list();

        for (String name : qconfigTargetDirlist) {
            for (String filename : configFiles.get(getAppCode()).replace("\t", "").replace(" ", "").split("\n")) {
                String qconfigFileToDelete = Dictionary + "/" + filename;
                if (name.equals(filename)) {
                    Boolean status2 = FileAndDirDeepDeletion.deleteFile(qconfigFileToDelete);
                    if (!status2) {
                        AegisLog.log("delete " + qconfigFileToDelete + " failed!");
                    }
                    continue;
                }
            }
        }
    }

    protected void touchFileIfNotExsit(String appCode, String filenames) {
        List<String> qconfigFileNameList = Splitter.on(separator).trimResults().splitToList(filenames);
        touchFileIfNotExsit(appCode, qconfigFileNameList);
    }

    protected static void touchFileIfNotExsit(String appCode, List<String> qconfigFileNameList) {
        for (int j = 0; j < qconfigFileNameList.size(); j++) {
            if (qconfigFileNameList.get(j).isEmpty()) {
                break;
            } else {
                File fInTestResources = new File(resourcesPath + "qconfig_test/" + appCode + "/" + qconfigFileNameList.get(j).toLowerCase());
                if (!fInTestResources.exists()) {
                    try {
                        AegisLog.log(fInTestResources.getName() + "不存在，创建空文件");
                        fInTestResources.createNewFile();
                        if (fInTestResources.getName().endsWith(".json")) {
                            FileWriter fileWritter = new FileWriter(fInTestResources.getPath(), false);
                            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
                            bufferWritter.write("[]");
                            bufferWritter.close();
                            fileWritter.close();
                        }
                    } catch (IOException e) {
                        AegisLog.error(e);
                    }
                } else {
                    AegisLog.log(fInTestResources.getName() + "已存在");
                }
            }
        }
    }

    private static File loadConfigToFile(String filename) {
        try {
            String path = resourcesPath + filename;
            File file = new File(path);
            InputStream in = new BufferedInputStream(new FileInputStream(path));
            boolean isUTF = FileCharsetCheck.canDecode(in, Charset.forName("UTF-8"));
            in.close();
            if (!isUTF) {
                FileEncodeConvert.convert(file, "GBK", "UTF-8");
            }

            if (!file.exists()) {
                return null;
            } else {
                if (!file.canRead()) {
                    AegisLog.info("无法读取配置文件." + file.getName());
                }

                return file;
            }
        } catch (Exception var5) {
            AegisLog.error(var5);
            return null;
        }
    }

    private static void getQconfigFileToLocal() {
        getQconfigFileToLocal(qtrace, "QTrace");
        getQconfigFileToLocal(tc_qmq_client, "tc_qmq_client");
        getQconfigFileToLocal(tc_public_config, "tc_public_config");
        getQconfigFileToLocal(b_info_encrypt, "b_info_encrypt");
        getQconfigFileToLocal(b_info_decrypt, "b_info_decrypt");
        getQconfigFileToLocal(b_info_transform, "b_info_transform");
        for (String app : appConfig.keySet()) {
            getQconfigFileToLocal(appConfig.get(app), app);
        }
    }

    private void getQconfigFileToTestResources() {
        renameCacheFilesToLocal("QTrace");
        renameCacheFilesToLocal("tc_qmq_client");
        renameCacheFilesToLocal("tc_public_config");
        renameCacheFilesToLocal("b_info_encrypt");
        renameCacheFilesToLocal("b_info_decrypt");
        renameCacheFilesToLocal("b_info_transform");
        for (String app : appConfig.keySet()) {
            renameCacheFilesToLocal(app);
        }
    }

    private static void getQconfigFileToLocal(String fileNames, String groupName) {
        getQconfigPropertiesToCache(fileNames, groupName);

    }

    private static void getQconfigPropertiesToCache(String fileNames, String groupName) {
        List<String> result = Splitter.on(separator).trimResults().splitToList(fileNames);
        //判断本地
        for (int i = 0; i < result.size(); i++) {
            if (!result.get(i).isEmpty()) {
                AegisLog.log("下载文件到本地cache: " + getCachePath() + result.get(i));
                MapConfig.get(groupName, result.get(i), Feature.DEFAULT);
            }
        }
    }

    private static String getCachePath() {
        return QunarFileUtil.getQunarStore().replace("\\", "/") + "/qconfig/";
    }

    private File newVersionCacheDictionary() {
        //qconfig-client新版本(1.5.11)
        File CONF_HOME = new File(QunarFileUtil.getQunarStore().replace("\\", "/"));
        String appCode = new MockQconfig().getAppCode();
        CONF_HOME = new File(CONF_HOME, appCode + "/qconfig/");
        return CONF_HOME;
    }

    private File oldVersionCacheDictionary() {
        //qconfig-client旧版本(1.2.2)
        File CONF_HOME = new File(QunarFileUtil.getQunarStore().replace("\\", "/"), "qconfig/");
        return CONF_HOME;
    }

    private File cacheDictionary() {
        File CONF_HOME = null;
        if (isNewVersion) {
            CONF_HOME = newVersionCacheDictionary();
        } else {
            CONF_HOME = oldVersionCacheDictionary();
        }
        return CONF_HOME;
    }

    private void renameCacheFilesToLocal(String groupName) {
        String SNAPSHOT_DIR = "/snapshot2/";
        String property = resourcesPath + "qconfig_test/" + groupName + "/";
        File snapFile = new File(cacheDictionary(), groupName + SNAPSHOT_DIR);
        File propertyFile = new File(property);
        snapFile.mkdirs();
        propertyFile.mkdirs();
        boolean isDirectory = snapFile.isDirectory() && propertyFile.isDirectory();
        if (!isDirectory) { // 如果不是文件夹，就返回
            AegisLog.log(snapFile + "不是文件夹！\n or");
            AegisLog.log(propertyFile + "不是文件夹！");
        }
        String[] snapFiles = snapFile.list();
        for (int i = 0; i < snapFiles.length; i++) { // 遍历该文件夹下的所有文件
            String oldsnapFileName = snapFiles[i];
            String cacheFileName = snapFile + "/" + oldsnapFileName;
            File cacheFile = new File(cacheFileName.toLowerCase());
            String newFileName = oldsnapFileName.substring(0, oldsnapFileName.lastIndexOf("."));
            newFileName = newFileName.substring(0, newFileName.lastIndexOf("."));
            newFileName = property + "/" + newFileName;
            File newFile = new File(newFileName.toLowerCase());
            Boolean result = cacheFile.renameTo(newFile);
            if (result)
                AegisLog.log("Copy cacheFile to resources success: " + newFileName);
        }
    }
}
